import java.io.BufferedWriter;
import java.util.*;

class ArrivalProcessor extends Proc {
	public int[] accumulatedJobs0 = new int[G.NUMBER_OF_DB_PROCESSORS];
	public int[] accumulatedJobs1 = new int[G.NUMBER_OF_DB_PROCESSORS];
	public int[] accumulatedJobs2 = new int[G.NUMBER_OF_DB_PROCESSORS];
	public int noMeasurements = 0;
	public int numberArrivals = 0;
	public int busyServers = 0;
	private int counter = 0;
	
	BufferedWriter measurementFile;

	public static dbProcessorV2 dbProcessorNetwork[];

	Random slump = new Random();

	ArrivalProcessor(BufferedWriter file) {
		dbProcessorNetwork = new dbProcessorV2[G.NUMBER_OF_DB_PROCESSORS];
		
		measurementFile = file;

		for (int i = 0; i < dbProcessorNetwork.length; i++) {
			dbProcessorNetwork[i] = new dbProcessorV2(null, i);
		}
	}

	public void TreatSignal(Signal x) {
		switch (x.signalType) {
		case G.ARRIVAL_LU_REQUEST: {
			numberArrivals++;
			int i = getDestination();
			switch (G.OVERLOAD_ALGORITHM) {
			case G.NO_CONTROL: {
				SignalList.SendSignal(G.ARRIVAL_JOB_1, dbProcessorNetwork[i],
						x.arrivalTime + G.MEAN_SERVICE_TIME_ARRIVAL_PROCESSOR, x.arrivalTime, false);
			}
				break;
			case G.TOTAL: {
				// changed to job_0 to run the overload control algorithm first.
				SignalList.SendSignal(G.ARRIVAL_JOB_0, dbProcessorNetwork[i],
						x.arrivalTime + G.MEAN_SERVICE_TIME_ARRIVAL_PROCESSOR, x.arrivalTime, false);
			}
				break;
			case G.WEIGHTED: {
				// changed to job_0 to run the overload control algorithm first.
				SignalList.SendSignal(G.ARRIVAL_JOB_0, dbProcessorNetwork[i],
						x.arrivalTime + G.MEAN_SERVICE_TIME_ARRIVAL_PROCESSOR, x.arrivalTime, false);
			}
				break;
			}
		}
			break;
		case G.MEASURE: {
			noMeasurements++;
			for (int i = 0; i < dbProcessorNetwork.length; i++) {
				accumulatedJobs0[i] += dbProcessorNetwork[i].numberInQueue_job0;
				accumulatedJobs1[i] += dbProcessorNetwork[i].numberInQueue_job1;
				accumulatedJobs2[i] += dbProcessorNetwork[i].numberInQueue_job2;
				
				if(!dbProcessorNetwork[i].queue.isEmpty())
					busyServers++;
////				
//				accumulatedJobs0[i] += dbProcessorNetwork[i].queue.size();
//				accumulatedJobs1[i] += dbProcessorNetwork[i].queue.size();
//				accumulatedJobs2[i] += dbProcessorNetwork[i].queue.size();
//				System.out.println("queue " + i + " size " + (dbProcessorNetwork[i].numberInQueue_job2));
			}
			
			SignalList.SendSignal(G.MEASURE, x.destination, G.time
					+ G.MEASUREMENT_TIME);
			
			try{	
				measurementFile.write(dbProcessorNetwork[1].locationUpdateDb + "\n");
		    }catch (Exception e){
		    	System.err.println("Error: " + e.getMessage());
		    }
			
		}
			break;
		}
	}

	private int getDestination() {
		// Place the dispatcher algorithm here
		int dest = 0;

		switch (G.ALGORITHM) {
		case G.RANDOM: {
			dest = slump.nextInt(G.NUMBER_OF_DB_PROCESSORS);
		}
			break;
		case G.ROUND_ROBIN: {
			counter++;
			if (counter == G.NUMBER_OF_DB_PROCESSORS)
				counter = 0;
			dest = counter;
		}
			break;
		case G.SMALLEST_JOBS_N1: {
			int minNumber = Integer.MAX_VALUE;
			ArrayList<Integer> sameSize = new ArrayList<Integer>();

			for (int j = 0; j < G.NUMBER_OF_DB_PROCESSORS; j++) {
				int numberQueue = (dbProcessorNetwork[j].numberInQueue_job1);
				if (numberQueue == minNumber)
					sameSize.add(j);
				if (numberQueue < minNumber) {
					sameSize.clear();
					sameSize.add(j);
					minNumber = numberQueue;
				}
			}
			dest = sameSize.get(slump.nextInt(sameSize.size()));
		}
			break;
		case G.SMALLEST_JOBS_N2: {
			int minNumber = Integer.MAX_VALUE;
			ArrayList<Integer> sameSize = new ArrayList<Integer>();

			for (int j = 0; j < G.NUMBER_OF_DB_PROCESSORS; j++) {
				int numberQueue = (dbProcessorNetwork[j].numberInQueue_job2);
				if (numberQueue == minNumber)
					sameSize.add(j);
				if (numberQueue < minNumber) {
					sameSize.clear();
					sameSize.add(j);
					minNumber = numberQueue;
				}
			}
			dest = sameSize.get(slump.nextInt(sameSize.size()));
		}
			break;
		case G.SHORT_QUEUE: {
			int minNumber = Integer.MAX_VALUE;
			ArrayList<Integer> sameSize = new ArrayList<Integer>();

			for (int j = 0; j < G.NUMBER_OF_DB_PROCESSORS; j++) {
				int numberQueue = (dbProcessorNetwork[j].numberInQueue_job1 + dbProcessorNetwork[j].numberInQueue_job2);
				if (numberQueue == minNumber)
					sameSize.add(j);
				if (numberQueue < minNumber) {
					sameSize.clear();
					sameSize.add(j);
					minNumber = numberQueue;
				}
			}
			// pick a db_processor among the processors with minimum and same
			// number of jobs
			dest = sameSize.get(slump.nextInt(sameSize.size()));
		}
			break;
		}
		return dest;
	}
}
